﻿using System;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using mimosa.Utilities;
using log4net;

namespace mimosa.SIP
{
    public class SIPMessage
    {
        private const string SIP_RESPONSE_PREFIX = "SIP";
        private const string SIP_MESSAGE_IDENTIFIER = "SIP";	// String that must be in a message buffer to be recognised as a SIP message and processed.

        private static int m_sipFullVersionStrLen = SIPConstants.SIP_FULLVERSION_STRING.Length;
        private static int m_minFirstLineLength = 7;
        private static string m_CRLF = SIPConstants.CRLF;

        private static ILog logger = AppState.logger;

        public string RawMessage;
        public SIPMessageTypesEnum SIPMessageType = SIPMessageTypesEnum.Unknown;
        public string FirstLine;
        public string[] SIPHeaders;
        public string Body;
        public byte[] RawBuffer;

        public DateTime ReceivedAt = DateTime.MinValue;
        public IPEndPoint ReceivedFrom;

        public static SIPMessage ParseSIPMessage(byte[] buffer, IPEndPoint receivedFrom)
        {
            string message = null;

            try
            {
                if (buffer == null || buffer.Length < m_minFirstLineLength)
                {
                    // Ignore.
                    return null;
                }
                else if (buffer.Length > SIPConstants.SIP_MAXIMUM_LENGTH)
                {
                    //logger.Error("SIP message received that exceeded the maximum allowed message length, ignoring.");
                    return null;
                }
                //else if (!ByteBufferInfo.HasString(buffer, SIP_MESSAGE_IDENTIFIER, m_CRLF))
                //{
                //    // Message does not contain "SIP" anywhrere on the first line, ignore.
                //    return null;
                //}
                else
                {
                    message = Encoding.UTF8.GetString(buffer);
                    SIPMessage sipMessage = ParseSIPMessage(message, receivedFrom);
                    sipMessage.RawBuffer = buffer;

                    return sipMessage;
                }
            }
            catch (Exception excp)
            {
                message = message.Replace("\n", "LF");
                message = message.Replace("\r", "CR");
                logger.Error("Exception ParseSIPMessage. " + excp.Message + "\nSIP Message=" + message + ".");
                return null;
            }
        }

        public static SIPMessage ParseSIPMessage(string message, IPEndPoint receivedFrom)
        {
            try
            {
                SIPMessage sipMessage = new SIPMessage();
                sipMessage.ReceivedAt = DateTime.Now;
                sipMessage.ReceivedFrom = receivedFrom;

                sipMessage.RawMessage = message;
                int endFistLinePosn = message.IndexOf(m_CRLF);

                if (endFistLinePosn != -1)
                {
                    sipMessage.FirstLine = message.Substring(0, endFistLinePosn);

                    if (sipMessage.FirstLine.Substring(0, 3) == SIP_RESPONSE_PREFIX)
                    {
                        sipMessage.SIPMessageType = SIPMessageTypesEnum.Response;
                    }
                    else
                    {
                        sipMessage.SIPMessageType = SIPMessageTypesEnum.Request;
                    }

                    int endHeaderPosn = message.IndexOf(m_CRLF + m_CRLF);
                    if (endHeaderPosn == -1)
                    {
                        // Assume flakey implementation if message does not contain the required CRLFCRLF sequence and treat the message as having no body.
                        string headerString = message.Substring(endFistLinePosn + 2, message.Length - endFistLinePosn - 2);
                        sipMessage.SIPHeaders = Regex.Split(headerString, m_CRLF);
                    }
                    else
                    {
                        string headerString = message.Substring(endFistLinePosn + 2, endHeaderPosn - endFistLinePosn - 2);
                        sipMessage.SIPHeaders = Regex.Split(headerString, m_CRLF);

                        if (message.Length > endHeaderPosn + 4)
                        {
                            sipMessage.Body = message.Substring(endHeaderPosn + 4);
                        }
                    }

                    return sipMessage;
                }
                else
                {
                    logger.Error("Error ParseSIPMessage, there were no end of line characters in the string being parsed.");
                    return null;
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception ParseSIPMessage. " + excp.Message + "\nSIP Message=" + message + ".");
                return null;
            }
        }
    }
}
